package com.nokia.example3dgame;

import java.util.Random;

import javax.microedition.lcdui.Graphics;
import javax.microedition.m3g.*;

public class Game3DManager {

	private Graphics3D graphics3D;

	private PlayerModel playerCamera;

	private Random rnd;

	private int canvasWidth;

	private int canvasHeight;

	private int score;

	private int numberOfAliens;

	private World scene;

	private static final int FLOOR_LEN = 20;

	private GameStatusListener status;

	public Game3DManager(int canvasWidth, int canvasHeight) {
		this.numberOfAliens = 10;
		this.score = 0;
		this.canvasWidth = canvasWidth;
		this.canvasHeight = canvasHeight;
		this.graphics3D = Graphics3D.getInstance();
		rnd = new Random();
		scene = new World(); // create scene graph
		buildScene();

	}

	public void paint(Graphics g) {
		try {
			graphics3D.bindTarget(g);
			graphics3D.render(scene);
			graphics3D.releaseTarget();
		} catch (IllegalStateException illegal) {
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void buildScene() {
		addCamera();
		addLights();
		addBackground();
		addFloor();
		addAliens();
	}

	private void addAliens() {
		AlienModel em;
		float x, z;
		for (int i = 0; i < numberOfAliens; i++) {
			x = rndCoord();
			z = rndCoord();
			em = new AlienModel(x, z);
			scene.addChild(em.getModel());
		}
	}

	private float rndCoord() {
		float f = rnd.nextFloat(); // 0.0f to 1.0f
		float coord = (f * FLOOR_LEN) - FLOOR_LEN / 2.0f;
		return coord;
	}

	private void addCamera() {
		playerCamera = new PlayerModel(canvasWidth, canvasHeight);
		scene.addChild(playerCamera.getCameraGroup());
		scene.setActiveCamera(playerCamera.getCamera());
	}

	private void addLights() {
		Light light = new Light(); // default white, directional light
		light.setIntensity(2.5f); // make it a bit brighter
		light.setOrientation(-65.0f, 1.0f, 0, 0); // pointing down and into
		scene.addChild(light);

	}

	private void addBackground() {
		Background backGnd = new Background();
		Image2D backIm = loadImage2D("/game/background.png");
		if (backIm != null) {
			backGnd.setImage(backIm);
		} else {
			backGnd.setColor(0x000000);
		}
		scene.setBackground(backGnd);

	}

	private void addFloor() {
		Image2D floorIm = loadImage2D("/game/floor.png");
		FloorTiles f = new FloorTiles(floorIm, FLOOR_LEN);
		scene.addChild(f.getFloorMesh());
	}

	private Image2D loadImage2D(String fn) {
		Image2D im = null;
		try {
			im = (Image2D) Loader.load(fn)[0];
		} catch (Exception e) {
			System.out.println("Cannot make image from " + fn);
		}
		return im;
	}

	public int updateGame() {

		float[] pos = playerCamera.getPosition();
		int maxPos = FLOOR_LEN / 2;
		if ((-maxPos < pos[0]) && (pos[0] < maxPos) && (-maxPos < pos[2])
				&& (pos[2] < maxPos)) {
			playerCamera.updatePosition();
		} else if (status != null) {
			status.gameOver(GameStatusListener.PLAYER_DIED);
		}

		if (numberOfAliens <= 0) {
			if (status != null) {
				status.gameOver(GameStatusListener.GAME_COMPLETED);
			}
		}
		return score;
	}

	public void setFirePressed() {
		RayIntersection ri = new RayIntersection();
		float[] camPos = playerCamera.getPosition(); // camera's current
													 // position
		float[] camDir = playerCamera.getDirection(); // camera's current
													  // direction

		if (scene.pick(-1, camPos[0], camPos[1], camPos[2], camDir[0],
				camDir[1], camDir[2], ri)) { // hit something?
			float distance = ri.getDistance();//normalize dist to the hit thing
			Node selected = ri.getIntersected();
			if (selected instanceof Mesh) {
				Mesh m = (Mesh) selected;
				m.setAppearance(0, AlienModel.getFrozenAppearance());
				m.setPickingEnable(false);
				score += 10;
				numberOfAliens--;
			}
		}

	}

	public void setKeysPressed(boolean leftPressed, boolean rightPressed,
			boolean upPressed, boolean downPressed) {
		playerCamera.setKeysPressed(leftPressed, rightPressed, upPressed,
				downPressed);
	}

	public void setGameStatusListener(GameStatusListener status) {
		this.status = status;

	}
}